<template>
	<view class="page mystic">
		<view class="brand-header"></view>
		<view class="card card-hover fancy-border mystic-card" style="margin-top:-80rpx; padding:24rpx 20rpx;">
			<text class="title glow">塔罗占卜</text>
			<view class="divider"></view>
			<!-- 牌阵选择 -->
			<view class="mode">
				<text class="label">牌阵：</text>
				<picker :range="spreadNames" :value="spreadIndex" @change="onSpreadChange">
					<view class="picker">{{ spreadNames[spreadIndex] || '加载中' }}</view>
				</picker>
			</view>
			<!-- 逆位概率与种子 -->
			<view class="controls">
				<view class="row">
					<text class="label">逆位概率：</text>
					<slider :value="Math.round(reversalProb*100)" @changing="e=>reversalProb = (e.detail.value||0)/100" @change="e=>reversalProb = (e.detail.value||0)/100"></slider>
					<text class="value">{{ Math.round(reversalProb*100) }}%</text>
				</view>
				<view class="row">
					<text class="label">种子：</text>
					<input class="seed" type="text" v-model="seed" placeholder="留空为随机" />
				</view>
			</view>
			<view class="actions">
				<button class="btn btn-primary btn-pill btn-wide" @click="startRitual">进入仪式</button>
			</view>

			<!-- 单张/每日 展示 -->
			<view v-if="(spreadKey==='single'||spreadKey==='daily') && singleCard" :class="['card','card-hover','result-card','flippable', revealIndex>0?'revealed':'']" style="margin-top:12rpx; padding:20rpx;">
				<text class="card-title">{{ singleCard.name }} <text class="tag">{{ singleCard.reversed? '逆位' : '正位' }}</text></text>
				<view class="meanings">
					<text class="m-title">要点</text>
					<view class="m-list">
						<text v-for="(m,i) in singleCard.points" :key="i" class="m-item">• {{ m }}</text>
					</view>
				</view>
				<!-- 分类解读 -->
				<view class="groups">
					<view class="g" v-for="(items, key) in singleCard.groups" :key="key">
						<text class="g-title">{{ iconForGroup(key) }} {{ key }}</text>
						<view class="m-list"><text class="m-item" v-for="(m,i) in items" :key="key+i">• {{ m }}</text></view>
					</view>
				</view>
				<view class="summary-block">
					<text class="summary-title">综合解读</text>
					<text class="summary-text">{{ singleSummary }}</text>
				</view>
				<view class="summary"><text>积极度：{{ singleCard.positivity }} / 100</text></view>
			</view>

			<!-- 三张 展示 -->
			<view v-if="spreadKey==='three' && trio.cards.length" class="card card-hover result-card" style="margin-top:12rpx; padding:20rpx;">
				<text class="card-title">三张：过去 / 现在 / 未来</text>
				<view class="trio">
					<view v-for="(c,i) in trio.cards" :key="i" :class="['trio-item','flippable', revealIndex>i?'revealed':'']">
						<text class="trio-pos">{{ ['过去','现在','未来'][i] }}</text>
						<text class="trio-name">{{ c.name }} <text class="tag">{{ c.reversed? '逆位' : '正位' }}</text></text>
						<text class="trio-point" v-for="(m,mi) in c.points" :key="mi">• {{ m }}</text>
					</view>
				</view>
				<view class="summary-block">
					<text class="summary-title">综合解读</text>
					<text class="summary-text">{{ trioSummary }}</text>
				</view>
				<view class="summary"><text>积极度：{{ trio.positivity }} / 100</text></view>
			</view>

			<!-- 凯尔特十字 展示 -->
			<view v-if="spreadKey==='celtic' && celtic.cards.length" class="card card-hover result-card" style="margin-top:12rpx; padding:20rpx;">
				<text class="card-title">凯尔特十字</text>
				<view class="celtic">
					<view v-for="(c,i) in celtic.cards" :key="i" :class="['celt-item','flippable', revealIndex>i?'revealed':'']">
						<text class="celt-pos">{{ c.pos }}</text>
						<text class="celt-name">{{ c.name }} <text class="tag">{{ c.reversed? '逆位' : '正位' }}</text></text>
						<text class="celt-point" v-for="(m,mi) in c.points" :key="mi">• {{ m }}</text>
					</view>
				</view>
				<view class="summary-block">
					<text class="summary-title">综合解读</text>
					<text class="summary-text">{{ celticSummary }}</text>
				</view>
				<view class="summary"><text>积极度：{{ celtic.positivity }} / 100</text></view>
			</view>
		</view>

		<!-- 仪式覆盖层 -->
		<view v-if="ritual.visible" class="ritual-overlay">
			<view class="ritual-box">
				<view v-if="ritual.step==='breath'" class="ritual-step">
					<view class="breath">
						<view class="pulse"></view>
						<text class="breath-count">{{ ritual.breath }}</text>
						<text class="breath-tip">缓慢吸气 · 缓慢呼气</text>
					</view>
				</view>
				<view v-else-if="ritual.step==='intention'" class="ritual-step">
					<text class="ritual-title">在心中设定你的意念</text>
					<input class="ritual-input" v-model="intention" placeholder="例如：我想获得关于××的指引" />
					<button class="btn btn-primary btn-block btn-pill" @click="toShuffle">开始洗牌</button>
				</view>
				<view v-else-if="ritual.step==='shuffle'" class="ritual-step">
					<text class="ritual-title">正在洗牌…</text>
					<view class="shuffle-deck" :class="{ anim: shuffling }"></view>
				</view>
			</view>
		</view>
	</view>
</template>

<script>
function fyShuffle(arr, rnd) { const a = arr.slice(); for (let i=a.length-1;i>0;i--) { const j = Math.floor(rnd()*(i+1)); [a[i],a[j]]=[a[j],a[i]] } return a }
function seedRandom(seed) { let x = 0; for (let i=0;i<seed.length;i++) x = (x*31 + seed.charCodeAt(i)) >>> 0; return function() { x^=x<<13; x^=x>>>17; x^=x<<5; x>>>=0; return (x%100000)/100000 } }
export default {
	data() {
		return {
			cards: [],
			spreadIndex: 0,
			spreadNames: ['单张','三张'],
			spreadKey: 'single',
			spreadsCfg: null,
			reversalProb: 0.5,
			seed: '',
			singleCard: null,
			trio: { cards: [], positivity: 0 },
			celtic: { cards: [], positivity: 0 },
			lastSeed: '',
			useCloud: true,
			keywordsMap: {},
			// 仪式
			ritual: { visible: false, step: 'breath', breath: 3 },
			intention: '',
			shuffling: false,
			revealIndex: 0,
			lastDrawSeed: ''
		}
	},
	computed:{},
	onLoad() {
		this.loadCards();
		this.loadSpreads();
		this.loadKeywords();
		try { this.lastSeed = uni.getStorageSync('last_tarot_seed') || '' } catch(e) {}
	},
	methods: {
		loadKeywords(){ try { uni.request({ url: '/static/tarot_keywords.json', success: (res)=>{ this.keywordsMap = (res && res.data) || {} } }) } catch(e) { this.keywordsMap = {} } },
		async loadSpreads(){
			try { uni.request({ url: '/static/tarot_spreads.json', success: (res)=>{
				const cfg = res && res.data; if (cfg && cfg.spreads) {
					this.spreadsCfg = cfg.spreads;
					const entries = ['daily','single','three','celtic'].filter(k=>cfg.spreads[k]).map(k=>({ key:k, name: cfg.spreads[k].name }));
					this.spreadNames = entries.map(e=>e.name);
					this.spreadIndex = 1; // 默认单张
					this.spreadKey = entries[this.spreadIndex]?.key || 'single';
				}
			}}) } catch(e) {}
		},
		async loadCards() { try { if (this.useCloud && uniCloud) { await uniCloud.callFunction({ name: 'get-config' }); const res = await uniCloud.callFunction({ name: 'get-tarot' }); if (res && res.result && res.result.data && Array.isArray(res.result.data.cards) && res.result.data.cards.length) { this.cards = res.result.data.cards; return } } } catch(e) {} uni.request({ url: '/static/tarot_cards_major.json', success: (res)=>{ if (res.statusCode===200 && res.data && Array.isArray(res.data.cards)) this.cards = res.data.cards }}) },
		onSpreadChange(e){ this.spreadIndex = e.detail.value; const keyMap = this.listSpreadKeys(); this.spreadKey = keyMap[this.spreadIndex] || 'single' },
		listSpreadKeys(){ if(!this.spreadsCfg) return ['single','three']; const order=['daily','single','three','celtic'].filter(k=>this.spreadsCfg[k]); return order },
		// 仪式流程
		startRitual(){ this.ritual.visible = true; this.ritual.step = 'breath'; this.ritual.breath = 3; const timer = setInterval(()=>{ if(this.ritual.breath>1){ this.ritual.breath--; } else { clearInterval(timer); this.ritual.step='intention'; } }, 1000) },
		toShuffle(){ this.ritual.step='shuffle'; this.shuffling = true; setTimeout(()=>{ this.shuffling=false; this.finishRitualDraw() }, 2200) },
		finishRitualDraw(){ const seed = this.seed && this.seed.trim() ? this.seed.trim() : String(Date.now()); this.drawWithSeed(seed); this.ritual.visible=false; this.revealSequence() },
		// 直接抽牌
		draw(){ const seed = this.seed && this.seed.trim() ? this.seed.trim() : String(Date.now()); this.drawWithSeed(seed); this.revealSequence() },
		redraw(){ if (this.lastSeed) { this.drawWithSeed(this.lastSeed); this.revealSequence() } },
		drawWithSeed(seed){ if (!this.cards.length) return; const rnd = seedRandom(seed); const deck = fyShuffle(this.cards, rnd); const rev = ()=> rnd() < this.reversalProb; const pickMeaning=(c,isRev)=> (isRev?c.reversedMeaning:c.uprightMeaning)||[]; this.lastDrawSeed = seed;
			if (this.spreadKey==='single' || this.spreadKey==='daily'){
				const picked = deck[0]; const isRev = rev(); const src = pickMeaning(picked,isRev);
				const points = src.slice(0,3);
				const groups = this.buildGroups(src, picked.name);
				const positivity = this.calcPositivity(src);
				this.singleCard = { name: picked.name, reversed: isRev, points, groups, positivity };
				this.trio = { cards: [], positivity: 0 }; this.celtic = { cards: [], positivity: 0 };
				this.saveHistory({ id: Date.now(), spread: this.spreadKey, cards: [{ cardId: picked.id, name: picked.name, reversed: isRev, position: 0 }], seed, report: { positivity, groups, points, intention: this.intention||'' } });
			} else if (this.spreadKey==='three'){
				const picks = deck.slice(0,3).map((c,i)=>({ id: c.id, name: c.name, reversed: rev(), points: pickMeaning(c,rev()).slice(0,2), position:i }));
				this.trio.cards = picks; const allPoints = picks.flatMap(p=>p.points); const posWords = /积极|胜利|创造|自由|合作|丰盛|洞察/; this.trio.positivity = Math.max(0, Math.min(100, Math.round((allPoints.filter(s=>posWords.test(s)).length / Math.max(1,allPoints.length)) * 100)));
				this.singleCard = null; this.celtic = { cards: [], positivity: 0 };
				this.saveHistory({ id: Date.now(), spread: 'three', cards: picks.map(p=>({ cardId: p.id, name: p.name, reversed: p.reversed, position: p.position })), seed, report: { positivity: this.trio.positivity, points: allPoints, intention: this.intention||'' } });
			} else if (this.spreadKey==='celtic'){
				const pos = (this.spreadsCfg && this.spreadsCfg.celtic && this.spreadsCfg.celtic.positions) || [];
				const picks = deck.slice(0,10).map((c,i)=>({ id:c.id, name:c.name, reversed: rev(), points: pickMeaning(c,rev()).slice(0,2), position:i, pos: (pos[i]&&pos[i].label)||('位置'+(i+1)) }));
				this.celtic.cards = picks; const allPoints = picks.flatMap(p=>p.points); this.celtic.positivity = this.calcPositivity(allPoints);
				this.singleCard = null; this.trio = { cards: [], positivity: 0 };
				this.saveHistory({ id: Date.now(), spread: 'celtic', cards: picks.map(p=>({ cardId: p.id, name: p.name, reversed: p.reversed, position: p.position, pos: p.pos })), seed, report: { positivity: this.celtic.positivity, points: allPoints, intention: this.intention||'' } });
			}
			try { uni.setStorageSync('last_tarot_seed', seed) } catch(e) {}
		},
		revealSequence(){
			this.revealIndex = 0;
			const total = (this.spreadKey==='single'||this.spreadKey==='daily') ? 1 : (this.spreadKey==='three'? 3 : 10);
			const step = 220; let i = 0;
			const tick = ()=>{
				if (i >= total) return;
				this.revealIndex = i+1;
				this.haptic();
				i++;
				if (i < total) setTimeout(tick, step);
			};
			setTimeout(tick, 120);
		},
		haptic(){ try{ if (uni.vibrateShort) uni.vibrateShort({}); else if (uni.vibrateLong) uni.vibrateLong({}); }catch(e){} },
		buildGroups(src, cardName){
			let list = this.normalizeMeanings(src);
			// 融合关键词映射（按卡牌名匹配）
			try {
				const kw = (this.keywordsMap && cardName) ? this.keywordsMap[cardName] : null;
				if (kw) {
					['love','career','advice','obstacle','timing'].forEach(k=>{ if (Array.isArray(kw[k])) list = list.concat(kw[k]) })
				}
			} catch(e) {}
			const pick = (re)=> list.filter(s=>re.test(s)).slice(0,3);
			const loveRe = /恋|爱|情|感情|关系|伴侣|婚|桃花|暧昧|亲密/;
			const careerRe = /事业|工作|职场|项目|升迁|成绩|学业|学习|考试|财务|金钱|收入|财富|投资/;
			const adviceRe = /建议|应|可|宜|尝试|调整|保持|避免|专注|行动|沟通|规划|复盘|坚持/;
			const obstacleRe = /阻碍|挑战|风险|困难|瓶颈|障碍|拖延|冲突|失衡|迷茫/;
			const timeRe = /时机|时间|近期|现在|过去|未来|阶段|节点|周期/;
			return { '爱情': pick(loveRe), '事业': pick(careerRe), '建议': pick(adviceRe), '阻碍': pick(obstacleRe), '时机': pick(timeRe) }
		},
		normalizeMeanings(src){ if (!src) return []; if (Array.isArray(src)) return src.map(s=>String(s)).filter(Boolean); if (typeof src === 'string') return src.split(/[,，;；\n]+/).map(s=>s.trim()).filter(Boolean); return [] },
		calcPositivity(arr){ const a = Array.isArray(arr)?arr:[]; const re = /积极|胜利|创造|自由|合作|丰盛|洞察|顺利|成长|好运/; return Math.max(0, Math.min(100, Math.round((a.filter(s=>re.test(s)).length / Math.max(1,a.length)) * 100))) },
		narrativeExplain(groups, positivity){
			const g = groups||{}; const p = positivity||0;
			const pick = (k)=> (g[k] && g[k].length) ? g[k][0] : '';
			return {
				love: pick('爱情'),
				career: pick('事业'),
				advice: pick('建议'),
				obstacle: pick('阻碍'),
				timing: pick('时机'),
				Tone: p>=70? '整体向好，适合把握推进' : (p<=35? '整体偏弱，建议先稳住节奏' : '整体中性，机会与挑战并存')
			}
		},
		buildNarrative(groups, positivity, ctx){
			// 1) 开头：意念 + 总体语气
			const s = this.narrativeExplain(groups, positivity);
			const intent = (ctx && ctx.intention) ? `围绕你此刻的意念“${ctx.intention}”，` : '';
			const first = `${intent}本次牌面${s.Tone}。`;
			// 2) 分项：按领域补充，最多取 3 条，语气自然
			const details = [];
			if (s.love)   details.push(`感情上，${s.love}`);
			if (s.career) details.push(`事业上，${s.career}`);
			if (s.obstacle) details.push(`当前阻碍在于${s.obstacle}`);
			if (s.advice) details.push(`建议，${s.advice}`);
			if (s.timing) details.push(`时机上，${s.timing}`);
			const middle = details.slice(0,3).join('。') + (details.length? '。' : '');
			// 3) 收尾：落到行动
			const last = s.advice ? '不妨据此制定一个小的可验证行动。' : '建议循序渐进，小步试探再决策。';
			return first + middle + last;
		},
		saveHistory(rec){ try { const key='tarot_history'; const old=uni.getStorageSync(key)||[]; old.push(rec); while(old.length>50) old.shift(); uni.setStorageSync(key, old) } catch(e) {} }
	},
	computed: {
		singleSummary(){ if(!this.singleCard) return ''; return this.buildNarrative(this.singleCard.groups, this.singleCard.positivity, { key:'single', names:[this.singleCard.name], reversed:this.singleCard.reversed, intention:this.intention||'' }) },
		trioSummary(){
			if(!this.trio || !this.trio.cards || !this.trio.cards.length) return '';
			const allPoints = this.trio.cards.flatMap(c=>c.points||[]);
			const groups = this.buildGroups(allPoints);
			return this.buildNarrative(groups, this.trio.positivity, { key:'three', names:this.trio.cards.map(c=>c.name), reversed: this.trio.cards.some(c=>c.reversed), intention:this.intention||'' });
		},
		celticSummary(){
			if(!this.celtic || !this.celtic.cards || !this.celtic.cards.length) return '';
			const allPoints = this.celtic.cards.flatMap(c=>c.points||[]);
			const groups = this.buildGroups(allPoints);
			return this.buildNarrative(groups, this.celtic.positivity, { key:'celtic', names:this.celtic.cards.slice(0,3).map(c=>c.name), reversed: this.celtic.cards.some(c=>c.reversed), intention:this.intention||'' });
		}
	}
}
</script>

<style lang="scss">
	.page { padding: 0 24rpx 24rpx; }
	/* 神秘高端主题 */
	.mystic { background: radial-gradient(120% 80% at 50% 0%, rgba(17,16,31,1) 0%, rgba(12,10,25,1) 40%, rgba(10,9,20,1) 100%); position: relative; }
	.mystic::before { content: ''; position: fixed; inset: 0; pointer-events: none; background-image: radial-gradient(1px 1px at 20% 30%, rgba(255,255,255,0.24), rgba(255,255,255,0)), radial-gradient(1px 1px at 80% 20%, rgba(255,255,255,0.18), rgba(255,255,255,0)), radial-gradient(1.2px 1.2px at 60% 70%, rgba(255,255,255,0.16), rgba(255,255,255,0)); background-repeat: no-repeat; }
	.glow { text-shadow: 0 2rpx 8rpx rgba(247,212,136,0.3), 0 0 20rpx rgba(107,91,149,0.35); }
	.mystic-card { background: rgba(255,255,255,0.06); border: 1rpx solid rgba(255,255,255,0.10); backdrop-filter: blur(8rpx); }
	.divider { height: 2rpx; width: 100%; margin: 10rpx 0 16rpx; background: linear-gradient(90deg, rgba(247,212,136,0), rgba(247,212,136,0.8), rgba(247,212,136,0)); }
	.title { font-size: 40rpx; color: #F9F8FF; margin-bottom: 8rpx; }
	.mode { display:flex; align-items:center; gap: 12rpx; margin: 8rpx 0 12rpx; }
	.picker { padding: 8rpx 12rpx; border: 1rpx solid rgba(255,255,255,0.18); background: rgba(255,255,255,0.04); color: #EAE8F8; border-radius: $brand-radius-md; }
	.actions { display: flex; gap: 12rpx; margin-bottom: 12rpx; align-items: center; }
	.btn-wide { width: 72%; max-width: 560rpx; margin: 0 auto; }
	.actions .btn { align-self: center; }
	/* Mystic 按钮增强对比与层次 */
	.mystic .btn-primary { background: linear-gradient(135deg, #7B6BAF, #B7A1E8 55%, #F7D488 100%); box-shadow: 0 10rpx 24rpx rgba(247,212,136,0.25), 0 4rpx 10rpx rgba(107,91,149,0.35); border: 1rpx solid rgba(247,212,136,0.55); color: #1A1530; }
	.fancy-border { position: relative; }
	.fancy-border::before { content:''; position:absolute; inset: -1rpx; border-radius: $brand-radius-lg; padding:1rpx; background: linear-gradient(135deg, rgba($brand-color-primary,0.35), rgba(255,255,255,0)); -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); -webkit-mask-composite: xor; mask-composite: exclude; pointer-events:none; }
	.controls { display:flex; flex-direction: column; gap: 12rpx; margin: 8rpx 0; }
	.row { display:flex; align-items:center; gap: 12rpx; }
	.label { color:#EAE8F8; }
	.value { color:#F9F8FF; min-width: 80rpx; text-align: right; font-weight: 700; }
	.seed { flex:1; height: 64rpx; border: 1rpx solid rgba(255,255,255,0.18); background: rgba(255,255,255,0.04); color: #EAE8F8; border-radius: $brand-radius-md; padding: 0 12rpx; }
	.seed::placeholder { color: rgba(234,232,248,0.6); }
	.tag { font-size: 24rpx; color: #C8C4E4; margin-left: 8rpx; }
	.card-title { font-size: 32rpx; color: #FFFFFF; }
	.m-title { margin-top: 12rpx; color: #F1EFF8; font-size: 28rpx; }
	.m-list { margin-top: 8rpx; display: flex; flex-direction: column; gap: 6rpx; }
	.m-item { color: #E6E4FB; line-height: 1.6; }
	.groups { display:grid; grid-template-columns: 1fr; gap: 8rpx; margin-top: 8rpx; }
	.g-title { font-weight: 700; color: #F1EFF8; margin-bottom: 4rpx; display:block; }
	.summary { margin-top: 12rpx; color: #EAE8F8; }
	.trio { display: flex; gap: 12rpx; }
	.trio-item { flex: 1; background: rgba(20,18,35,0.58); border: 1rpx solid rgba(255,255,255,0.14); border-radius: $brand-radius-lg; padding: 12rpx; }
	.trio-pos { font-weight: 600; color: $brand-color-accent; }
	.trio-name { color: #F1EFF8; }
	.trio-point { color: #E6E4FB; display:block; line-height: 1.6; }
	.celtic { display:grid; grid-template-columns: 1fr; gap: 10rpx; margin-top: 8rpx; }
	.celt-item { background: rgba(20,18,35,0.58); border: 1rpx solid rgba(255,255,255,0.14); border-radius: $brand-radius-lg; padding: 12rpx; }
	.celt-pos { font-weight: 600; color: $brand-color-accent; }
	.celt-name { color: #F1EFF8; }
	.celt-point { color: #E6E4FB; display:block; line-height: 1.6; }
	.result-card { background: rgba(20,18,35,0.58); border: 1rpx solid rgba(255,255,255,0.12); }
	.summary-block { margin-top: 10rpx; padding-top: 10rpx; border-top: 1rpx dashed rgba(255,255,255,0.15); }
	.summary-title { font-weight: 700; color: #F9F8FF; display:block; margin-bottom: 6rpx; }
	.summary-text { color: #E6E4FB; line-height: 1.7; }
	/* 仪式覆盖层与动画 */
	.ritual-overlay { position: fixed; inset: 0; background: linear-gradient(180deg, rgba(0,0,0,0.35), rgba(0,0,0,0.55)); backdrop-filter: blur(2px); display:flex; align-items:center; justify-content:center; z-index: 999; }
	.ritual-box { width: 86%; max-width: 640rpx; background:#fff; border-radius: $brand-radius-lg; padding: 24rpx; box-shadow: $brand-shadow-layer; }
	.ritual-step { display:flex; flex-direction: column; align-items:center; gap: 16rpx; }
	.ritual-title { font-size: 32rpx; font-weight: 700; color: $brand-color-heading; }
	.ritual-input { width: 100%; height: 72rpx; border: 1rpx solid $brand-color-border; border-radius: $brand-radius-md; padding: 0 16rpx; }
	.breath { display:flex; flex-direction: column; align-items:center; gap: 10rpx; padding: 12rpx 0; }
	.pulse { width: 160rpx; height: 160rpx; border-radius: 9999rpx; background: rgba($brand-color-primary, 0.12); box-shadow: 0 0 0 0 rgba($brand-color-primary, 0.45); animation: pulse 2s ease-in-out infinite; }
	.breath-count { font-size: 48rpx; font-weight: 700; color: $brand-color-primary; }
	.breath-tip { font-size: 24rpx; color: $brand-color-muted; }
	@keyframes pulse { 0% { transform: scale(0.92); box-shadow: 0 0 0 0 rgba(107,91,149, 0.45) } 70% { transform: scale(1); box-shadow: 0 0 0 24rpx rgba(107,91,149, 0) } 100% { transform: scale(0.92); box-shadow: 0 0 0 0 rgba(107,91,149, 0) } }
	.shuffle-deck { width: 160rpx; height: 100rpx; border-radius: 10rpx; border: 2rpx dashed rgba($brand-color-primary, 0.4); }
	.shuffle-deck.anim { background: repeating-linear-gradient(45deg, rgba($brand-color-primary, 0.15), rgba($brand-color-primary, 0.15) 8rpx, rgba(255,255,255,0.8) 8rpx, rgba(255,255,255,0.8) 16rpx); animation: sway 0.6s ease-in-out infinite alternate; }
	@keyframes sway { from { transform: rotate(-4deg) } to { transform: rotate(4deg) } }
	/* 翻牌动画 */
	.flippable { transform: perspective(800rpx) rotateY(90deg); transform-origin: center; opacity: 0; }
	.flippable.revealed { transition: transform $brand-dur-med $brand-ease-standard, opacity $brand-dur-med $brand-ease-standard; transform: perspective(800rpx) rotateY(0); opacity: 1; }
</style> 